package Jogo.Entities {
	import Jogo.Main;
	import Jogo.States.PhaseState;
	import Jogo.Util;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.MovieClip;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.ui.Mouse;
	import flash.utils.getTimer;
	
	import mx.flash.UIMovieClip;
	
	/** Describe one enemy of the game 
	 */
	public class Enemy extends Entity{
		/* Pictures */
		[Embed(source = "../../Img/PhaseState/Inimigo_lvl0.png")]
		private var enemy_lvl0BMP : Class; 
		[Embed(source = "../../Img/PhaseState/Inimigo_lvl1.png")]
		private var enemy_lvl1BMP : Class; 
		[Embed(source = "../../Img/PhaseState/Inimigo_lvl2.png")]
		private var enemy_lvl2BMP : Class; 
		[Embed(source = "../../Img/PhaseState/Inimigo_lvl3.png")]
		private var enemy_lvl3BMP : Class; 
		private var enemyImg : Bitmap;
		
		/* The constant to define the type of the enemies*/
		public static const ENEMY1 : int = 0;
		public static const ENEMY2 : int = 1;
		public static const ENEMY3 : int = 2;
		public static const ENEMY4 : int = 3;
		public static const ENEMY5 : int = 4;
		
		public static const ENEMY_WIDTH : int = 60;
		public static const ENEMY_HEIGHT : int = 43;
		
		public static const MONEY_DROPPED : int = 100;
		
		/* Describes the lines of the table below (For enemies)*/
		private const SPEED				: int = 0;
		private const HIT_POINTS		: int = 1;
		
		/* Matrix that contains the attributes of the turrets (one matrix for each turret):
		*			Level 1 	|	Level 2 	|	Level 3 	|	Level 4 	|	
		* Speed			X		|		X		|		X		|		X		|
		* Hit Points	X		|		X		|		X		|		X		|
		*/
		
		/* Enemy attributes */
		private var speed : Number;
		private var hp : Number; //hit points
		private var maxHp : Number;
		
		/* current position in the map
		 * based on the game resolution
		 */
		private var currentPosition : Point = new Point();
		
		/* The heading angle (in degrees) that the enemy facing. 
		 * Being the +x the 0º angle and -y the 90º
		 */
		private var angle : Number;
		private var lastAngle : Number;		
		
		/* Tiles */
		private var nextTile : Tile;
		private var currentTile : Tile;
		private var lastTile : Tile;
		
		private var enemy : MovieClip; //Holds the image of the enemy
		private var hpBarData : BitmapData; //Bar that shows the enemy Hit Points
		private var hpBar : Bitmap;
		
		/* Set if the enemy is in game. 
		 * If it's not inGame, the turrets can't hit it*/
		private var inGame : Boolean;
		
		public function Enemy(tile : Tile, type_p:int, level_p : int) {
			createEnemy();
			
			root = new MovieClip();
			level = level_p;
			
			switch(level){
				case 0:
					enemyImg = new enemy_lvl0BMP;
				break;
				case 1:
					enemyImg = new enemy_lvl1BMP;
				break;
				case 2:
					enemyImg = new enemy_lvl2BMP;
				break;
				case 3:
					enemyImg = new enemy_lvl3BMP;
				break;
			}
			
			enemyImg.width = ENEMY_WIDTH;
			enemyImg.height = ENEMY_HEIGHT;
			enemy = new MovieClip();
			//angle = new Vector.<Number>(2);
			inGame = false;
			hpBarData = new BitmapData(enemyImg.width, 10, true, 0xC800FF00);
			hpBar = new Bitmap(hpBarData);
			
			type = type_p;
			speed = entityV[SPEED][level];
			maxHp = entityV[HIT_POINTS][level]; 
			hp = maxHp;
			
			tile.insertEnemy(this);
			
			currentTile = tile;
			lastTile = null;
			nextTile = getNextTile();
			lastAngle = angle = 0;
			
			
			currentPosition = new Point(currentTile.getCenter().x, currentTile.getCenter().y);
			
			// Put the enemy BMP in the middle of the enemy MovieClip
			enemy.x = currentPosition.x; 
			enemy.y = currentPosition.y;
			root.addChild(enemy);
			enemyImg.x -= enemyImg.width/2;
			enemyImg.y -= enemyImg.height/2;
			enemy.addChild(enemyImg);
			hpBar.x -= enemyImg.width/2;
			hpBar.y -= (enemyImg.height/2 + hpBarData.height);
			enemy.addChild(hpBar);
			
			angle = Util.setRotation(new Point(enemy.x, enemy.y), new Point(nextTile.getCenter().x, nextTile.getCenter().y));
			
		}
		
		/** The update function for every frame 
		 */
		public function enterFrame() : int{
			//THIS MUST BE THE FIRST THING IN THIS FUNCTION
			if (hp <=0){
				return PhaseState.ENEMY_DIED;
			}
			
			return walk(); 
			return 0;
		}
		
		/* ESSE ASSUME SÓ TÁ AQUI POR CAUSA DO DATE. MAS COMO EU VOU TER QUE 
		 * MODIFICAR PRA TIRAR ESSE DATE, ESSE ASSUME VAI TER QUE SAIR, MANO
		 */		
		public function setInGame(b : Boolean) : void{
			inGame = b;
		}
		public function getInGame() : Boolean {
			return inGame;
		}
		
		private function equalSign(i:Number, j:Number): Boolean{
			if((i == 0) || (j==0)){
				return true;
			}
			
			if (i/j > 0){
				return true
			} else {
				return false
			}
		}
		
		/* Make the movement of the enemy */
		private function walk() : int{
			//Used when movement is based on time
			
			if (! inGame){
				angle = 0;
				enemy.rotation = angle;
				
				currentPosition.x += (speed)*Math.cos(angle * Math.PI/180);
				currentPosition.y += (speed)*Math.sin(angle * Math.PI/180);
				
				enemy.x = currentPosition.x; 
				enemy.y = currentPosition.y;
				
				if (enemy.x >= currentTile.getCenter().x + PhaseState.tileSide*2){
					return PhaseState.ENEMY_WON;
				}
				
				return 0;
				
			}
			lastAngle = angle;
			angle = Util.setRotation(new Point(enemy.x, enemy.y), new Point(nextTile.getCenter().x, nextTile.getCenter().y));
			/* If the signs of the last two angles are different
			 * then the enemy has changed its course.
			 * So it needs to get the next tile
			 */

			if (!equalSign(Math.cos(lastAngle), Math.cos(angle)) || !equalSign(Math.sin(lastAngle), Math.sin(angle))){
				
				lastTile = currentTile;
				currentTile = nextTile;
				nextTile = getNextTile();
				
				/* update the tile this enemy is */
				lastTile.removeEnemy(this);
				currentTile.insertEnemy(this);
				
				if (currentTile.getType() == Tile.END_POINT){ //the enemy won
					enemyWins();
					setInGame(false)
					return 0;
				}
				
				lastAngle = angle;
				if(nextTile == null){
					trace("é null");
				}
				angle = Util.setRotation(new Point(enemy.x, enemy.y), new Point(nextTile.getCenter().x, nextTile.getCenter().y));
			}
			
			/* Update the position and the angle */
			enemy.rotation = angle;

			//Use these lines if the movement is based only on enter frames
			currentPosition.x += (speed)*Math.cos(angle * Math.PI/180);
			currentPosition.y += (speed)*Math.sin(angle * Math.PI/180);
			
			enemy.x = currentPosition.x; 
			enemy.y = currentPosition.y;
			
			return 0;
		}
		
		
		public function getCurrentPosition() : Point {
			return currentPosition;
		}
		
		public function takeDamage(damage : int) : int{
			hp -= damage;
			
			//Shorten the width of the hp bar
			hpBar.width = hp/maxHp*enemyImg.width;
			
			if (hp <= 0){ //Enemy is dead
				destroy();
			}
			
			return hp;
		}
		
		private function destroy() : void{
			currentTile.removeEnemy(this);
			if (root.contains(enemy)){
				root.removeChild(enemy);
			}
		}
		
		/* Uses the enemy intelligence attribute to 
		 * set the next tile it will be heading
		 */
		private function getNextTile() : Tile {
			var i : int;
			var j : int;
			var next : Tile = null;
			var paths : Vector.<Tile> = new Vector.<Tile>;
			paths = currentTile.getPaths().concat();
			
			/* Algoritmo: pega o primeiro tile que for para a direita (mais próximo da saída)
			 * se existir mais de um caminho pra cima ou pra baixo, 50% de chances de pegar um ou outro
 			 * se não, pega o primeiro caminho que vai para a esquerda, excluindo o tile de onde o inimigo veio
			 */

			/* If the enemy is in a Start point it just returns random */
			if (currentTile.getType() == Tile.START_POINT){
				i = Math.floor(Math.random()*paths.length);
				return paths[i];
			}
			
			/* exclui o tile de onde o inimigo está vindo, para evitar que ele volte */
			if (lastTile != null){
				
				for (i = 0; i < paths.length; i++){
					if (paths[i] == lastTile){
						//esclui paths[i] do paths
						paths.splice(i, 1);
					}
				}
			}
			
			
			if (paths.length == 0){ //it's the last tile
				return null;
			}
			
			/* CHOOSE RANDOMLY. DON'T ENTER THE LINES BELOW */
			i = Math.floor(Math.random()*paths.length);
			return paths[i];
			
			// Pega o primeiro caminho que é pra direita
			for(i = 0; i<paths.length; i++){
				if(paths[i].getCenter().x > currentTile.getCenter().x){
					return paths[i];
				}
			}
			
			// Pega o primeiro caminho que for pra cima ou pra baixo
			for(i = 0; i<paths.length; i++){
				if(paths[i].getCenter().x == currentTile.getCenter().x){
					return paths[i];
				}
			}
			
			//Em último caso, retorna o primeiro que for pra esquerda
			return paths[0];
			
		}
		
		public function getCurrentTile() : Tile{
			return currentTile;
		}
		
		/* Called when the enemy reaches the destination point */
		private function enemyWins() : void{
			inGame = false; // The turret won't hit it
			
			currentTile.removeEnemy(this);
			
		}
		
		/* Creates the matrix 'entityV' that contains the attributes of each enemy
		 * based on it's level
		 */
		private function createEnemy() : void{ 
			entityV = new Vector.<Vector.<Number>>(5)
			for (var i : int = 0; i < 2; i++) { //Number of attributes (lines in the matrix above)
				entityV[i] = new Vector.<Number>(4); //Number of levels
			}
			
			switch (type){
				case ENEMY1:
					entityV[0][0] = 3;  entityV[0][1] = 5; 	entityV[0][2] = 8; 	entityV[0][3] = 3; // Speed
					entityV[1][0] = 20; entityV[1][1] = 15; entityV[1][2] = 50; entityV[1][3] = 150; // Hit Points
					
					break;
				
				case 2:
					//Fazer para todos os tipos de inimigos que existir.
					break;
				
				case 3:
					//lala
					break;
			}
		}
	}
}